import datetime
import random

from django.conf import settings
from django.contrib import messages
from django.core.exceptions import ValidationError
from django.db import transaction
from django.db.models import F
from django.forms import ModelForm
from django.shortcuts import render, redirect
from django.urls import reverse
from django_redis import get_redis_connection

from utils import video
from utils.bootstrap import BootstrapForm
from utils.pager import Pagination
from web.models import Order, PricePolicy, Customer, TransactionRecord


def my_order_list(request):
    queryset = Order.objects.all().order_by('-id')
    pager = Pagination(request, queryset)
    return render(request, 'my_order_list.html', {'pager': pager})


class MyOrderModelForm(BootstrapForm, ModelForm):
    class Meta:
        model = Order
        fields = ['url', 'count']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, *kwargs)
        queryset = PricePolicy.objects.all().order_by('count')
        help_text_list = []
        price_count_list = []
        for item in queryset:
            unit_price = item.price / item.count
            help_text_list.append(f'>={item.count} ￥{unit_price}/条')
            price_count_list.append([item.count, unit_price])
        if price_count_list:
            self.fields.get('count').help_text = '、'.join(help_text_list)
        else:
            self.fields.get('count').help_text = '请联系管理员设置价格'
        self.price_count_list = price_count_list

    def clean_count(self):
        count = self.cleaned_data['count']
        if not self.price_count_list:
            raise ValidationError('请联系管理员设置价格')

        min_count = self.price_count_list[0][0]
        if count < min_count:
            raise ValidationError(f'起购数量：{min_count}')
        return count


def my_order_add(request):
    if request.method == 'GET':
        form = MyOrderModelForm()
        return render(request, 'form.html', {'form': form})
    form = MyOrderModelForm(request.POST)

    if not form.is_valid():
        return render(request, 'form.html', {'form': form})

    # 获取客户提交的url和count
    video_url = form.cleaned_data['url']
    count = form.cleaned_data['count']
    # 4.2 爬虫，获取原播放量
    status, old_view_count = video.get_video_view_counts(video_url)
    if not status:
        form.add_error('count', '获取视频当前播放量失败')
        return render(request, 'form.html', {'form': form})

    # 1. 根据数量获取单价，计算原价
    unit_price = 0
    for inx in range(len(form.price_count_list) - 1, -1, -1):
        limit_count, unit_price = form.price_count_list[inx]
        if count >= limit_count:
            break
    total_price = count * unit_price

    # 数据库操作，要考虑事务+锁
    try:
        with transaction.atomic():
            # 2. 根据当前客户所属级别，计算实际折扣价格
            customer_obj = Customer.objects.filter(id=request.my_user.id).select_for_update().first()
            discount = customer_obj.level.percent
            real_price = total_price * discount / 100

            # 3. 判断当前账户余额是否足够
            if real_price > customer_obj.balance:
                form.add_error('count', '账户余额不足')
                return render(request, 'form.html', {'form': form})

            # 4. 创建订单
            # 4.1 生成订单号
            while True:
                oid = datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')
                random_code = random.randint(1000000, 9999999)
                oid += str(random_code)
                exists = Order.objects.filter(oid=oid).exists()
                if not exists:
                    break

            # 4.2 爬虫，获取原播放量
            # 见上面
            # 4.3 获取客户id
            form.instance.customer_id = request.my_user.id
            form.instance.oid = oid
            form.instance.price = total_price
            form.instance.real_price = real_price
            form.instance.old_view_count = old_view_count
            form.save()

            # 5. 账户扣款
            Customer.objects.filter(id=request.my_user.id).update(balance=F("balance") - real_price)
            # 6. 生成交易记录
            TransactionRecord.objects.create(
                charge_type=3,
                customer_id=request.my_user.id,
                amount=real_price,
                order_oid=oid,
            )
            # 7. 写入队列
            conn = get_redis_connection("default")
            conn.lpush(settings.QUEUE_TASK_NAME, oid)
    except Exception as e:
        form.add_error('count', '订单创建失败')
        return render(request, 'form.html', {'form': form})
    return redirect(reverse('my_order_list'))


def my_order_cancel(request, pk):
    """ 撤单，使用message组件 """
    # 1. 校验订单是否存在
    order_obj = Order.objects.filter(id=pk, active=1, status=1, customer=request.my_user.id).first()
    if not order_obj:
        messages.add_message(request, settings.MESSAGE_DANGER_TAG, '订单不存在')
        return redirect(reverse('my_order_list'))

    try:
        with transaction.atomic():
            # 2. 返还订单金额到余额
            real_price = order_obj.real_price
            Customer.objects.filter(id=request.my_user.id).select_for_update().update(balance=F("balance") + real_price)

            # 3. 生成交易记录
            TransactionRecord.objects.create(
                charge_type=5,
                customer_id=request.my_user.id,
                amount=real_price,
                order_oid=order_obj.oid,
            )
            # 4. 修改订单状态为已撤单
            Order.objects.filter(id=pk, active=1, status=1, customer=request.my_user.id).update(status=5)

            # 撤单提示
            messages.add_message(request, messages.SUCCESS, '撤单成功')
            return redirect(reverse('my_order_list'))
    except Exception as e:
        messages.add_message(request, settings.MESSAGE_DANGER_TAG, '撤单失败')
        return redirect(reverse('my_order_list'))
